//
//  PWAIOBlueManager.m
//  AirDream
//
//  Created by frank on 2024/5/20.
//

#import "PWAIOBlueHelper.h"
#import <CoreBluetooth/CoreBluetooth.h>
#import "PWDigitalUtils.h"
#import "BleModel.h"
#import "PWConstant.h"
#import "WifiUtils.h"
#import "PWGlobalMacro.h"
#import <UserNotifications/UNUserNotificationCenter.h>
#import <UserNotifications/UNNotificationSettings.h>

@interface PWAIOBlueHelper () <CBCentralManagerDelegate, CBPeripheralDelegate>

@property(nonatomic, assign) NSInteger CBState;

/** 蓝牙中心设备管理对象 */
@property (nonatomic, strong) CBCentralManager *mainManger;

@property(nonatomic, strong, nullable) PWPeripheralModel* connectPeripheralModel;
///写通道
@property(nonatomic, strong) CBCharacteristic* characteristicFFE4;
///读通道
@property(nonatomic, strong) CBCharacteristic* characteristicFFE3;
///TODO:会搜索到很多服务。进而搜索到很多重复的特征 FFE4，现在限制调用一次写入数据
@property(nonatomic, assign) BOOL isCalled;

@property(nonatomic, strong) NSMutableArray<BleModel *>* bleArray;
@property(nonatomic, strong) NSMutableArray<CBPeripheral *>* peripheralArray;

@property(nonatomic, strong) CBPeripheral* peripheral;

@property(nonatomic, assign) BOOL isOpenPushNoti;
///蓝牙中心状态
@property(nonatomic, assign) NSInteger bleCentralStatus;

@end

@implementation PWAIOBlueHelper

- (instancetype) init {
    if (self = [super init]) {
        self.mainManger = [[CBCentralManager alloc] initWithDelegate:self queue:dispatch_get_main_queue()];
        self.mainManger.delegate = self;
    }
    return self;
}
///蓝牙中心状态更新
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
    self.CBState = central.state;
    
    switch (central.state) {
        case CBManagerStateUnknown:
//            [QHPopUpView alterTitleViewAction:@"未知的蓝牙状态!"];
            NSLog(@"未知的蓝牙状态!");
            break;
        case CBManagerStateResetting:
            NSLog(@"重新连接中...");
            break;
        case CBManagerStateUnsupported:
            NSLog(@"蓝牙设备不支持");
            break;
        case CBManagerStateUnauthorized:
            NSLog(@"未授权蓝牙权限");
            self.bleCentralStatus = -1;
            break;
        case CBManagerStatePoweredOff:
            //            [QHPopUpView alterTitleViewAction:@"请开启蓝牙或靠近脑贴设备"];
            self.bleCentralStatus = 0;
            break;
        case CBManagerStatePoweredOn:
            self.bleCentralStatus = 1;
            break;
        default:
            //            [QHPopUpView alterTitleViewAction:@"蓝牙更改"];
            break;
    }
}
///扫描到蓝牙设备
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary<NSString *, id> *)advertisementData RSSI:(NSNumber *)RSSI {
    NSLog(@"=====%@", peripheral.name);
//    if ([peripheral.name hasPrefix:@"FLEX_AIO_4F"]) {
//        self.connectPeripheralModel = [[PWPeripheralModel alloc] init];
//        self.connectPeripheralModel.peripheral = peripheral;
//        [self connectWithPeripheral:self.connectPeripheralModel];
//    }
    
    if (![peripheral.name hasPrefix:@"FLEX_AIO"])       return;
    if ([self isContainDeviceName:peripheral.name])     return;
    
//    self.connectPeripheralModel = [[PWPeripheralModel alloc] init];
//    self.connectPeripheralModel.peripheral = peripheral;
//    [self connectWithPeripheral:self.connectPeripheralModel.peripheral];
    
    BleModel *model = [[BleModel alloc] init];
    model.channelName = @"scanDevice";
    
    model.code = 101;
    model.isConnected = NO;
    model.deviceName = peripheral.name;
    
    [self.bleArray addObject:model];
    [self.peripheralArray addObject:peripheral];
    
    NSDictionary *personDict = [model mj_keyValues];

//    self.eventSink(personDict);
    [self.methodChannel invokeMethod:eventScanAIO arguments:personDict];
    
}
///连接成功
- (void)centralManager:(CBCentralManager *)central didConnectPeripheral:(CBPeripheral *)peripheral {
    
    peripheral.delegate = self;
//    NSArray<CBUUID *> *services = @[[CBUUID UUIDWithString:@"0000ffe2-0000-1000-8000-00805f9b34fb"]];
    [peripheral discoverServices: nil]; // 扫描设备中的所有服务
    self.connectPeripheralModel = [[PWPeripheralModel alloc] init];
    self.connectPeripheralModel.peripheral = peripheral;
    
    BleModel *model = [self fetchBleModel:peripheral.name];
    model.isConnected = YES;
    NSDictionary *dict = [model mj_keyValues];
    
    [self.methodChannel invokeMethod:eventConnectStatus arguments:dict];
}
///连接断开
- (void)centralManager:(CBCentralManager *)central didDisconnectPeripheral:(CBPeripheral *)peripheral error:(nullable NSError *)error {
    NSLog(@"断开原因：%@", error.userInfo);
    BleModel *model = [self fetchBleModel:peripheral.name];
    model.isConnected = NO;
    NSDictionary *dict = [model mj_keyValues];
    
    [self.methodChannel invokeMethod:eventConnectStatus arguments:dict];
    
}
///扫描到蓝牙服务
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverServices:(nullable NSError *)error {

    for (CBService *needService in peripheral.services) {
        NSString *UUIDStr = [needService.UUID.UUIDString uppercaseString];
        [peripheral discoverCharacteristics:nil forService:needService];
        
        NSLog(@"服务：%@", UUIDStr);
//        break;
    }
    
}
///找到特征模块
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(nullable NSError *)error {
    if (error) {
        NSLog(@"写入数据:%@ 出错,原因是: %@",peripheral.name,error);
        return;
    }
    
    // 遍历服务中的特性，开启相应的通知和给特征写入数据，然后读取特征，搜索特征中的描述
    
    for(CBCharacteristic *character in service.characteristics){
        
        NSString *UUIDStr = [character.UUID.UUIDString uppercaseString];
        
        NSLog(@"特征: %@", UUIDStr);
        
        if ([UUIDStr isEqualToString:@"FFE3"]) {
//            [peripheral setNotifyValue:YES forCharacteristic:character];
            self.characteristicFFE3 = character;
        }
        
        if ([UUIDStr isEqualToString:@"FFE4"]) {
            self.characteristicFFE4 = character;
//            self.characteristicFFE4 = character;
//            [self sendCommand];
//            break;
        }
        
    }
    
}
- (void)peripheral:(CBPeripheral *)peripheral didModifyServices:(NSArray<CBService *> *)invalidatedServices {
    
}

- (void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    NSString *UUIDStr = characteristic.UUID.UUIDString;
    if(error){
        NSLog(@"设备:%@ 数据写入到特征(%@)中失败，原因是:%@",peripheral.name, UUIDStr, error.localizedDescription);
        return;
    }
    
    NSLog(@"数据写入到特征(%@)中成功!", UUIDStr);
    NSLog(@"数据写入到特征(%@)中成功!", characteristic.value);
}
- (void)peripheral:(CBPeripheral *)peripheral didUpdateValueForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error {
    NSLog(@"接收到数据：%@", characteristic.value);
    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
    [dic setValue:peripheral.name forKey:@"deviceName"];
    [dic setValue:characteristic.value forKey:@"cmd"];
    [self.methodChannel invokeMethod:eventBluetooth arguments:dic];
//    self.eventSink(characteristic.value);
}
//- (void)peripheral:(CBPeripheral *)peripheral didUpdateNotificationStateForCharacteristic:(CBCharacteristic *)characteristic error:(nullable NSError *)error{
//    NSString *UUIDStr = characteristic.UUID.UUIDString;
//    if(error){
//        NSLog(@"特征(%@)更新失败，原因是:%@",UUIDStr, error.userInfo);
////        return;
//    }
//    NSLog(@"通知状态改变 %@", characteristic.value);
//}
- (void) peripheral:(CBPeripheral *)peripheral didDiscoverDescriptorsForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error {
    if (error) {
        // 处理错误
        return;
    }

    for (CBDescriptor *descriptor in characteristic.descriptors) {
        [peripheral readValueForDescriptor:descriptor];
        
        // 写入描述符的值
        NSData *data = [@"0000fff2-0000-1000-8000-00805f9b34fb" dataUsingEncoding:NSUTF8StringEncoding];
        [peripheral writeValue:data forDescriptor:descriptor];

        // 订阅描述符的通知
        if (characteristic.properties & CBCharacteristicPropertyNotify) {
            [peripheral setNotifyValue:YES forCharacteristic:characteristic];
        }
    }
}

- (void) connectWithPeripheral:(CBPeripheral *) peripheral {
    [self.mainManger connectPeripheral:peripheral options:nil];
}
- (void) cancelWithPeripheral:(CBPeripheral *) peripheral {
    [self.mainManger cancelPeripheralConnection:peripheral];
}
///电量指令
- (void) eqCommand {
    
    NSLog(@"eqCommand");
    
    [self.connectPeripheralModel.peripheral setNotifyValue:YES forCharacteristic:self.characteristicFFE3];
    
    unsigned char cmdArr1[5];
    cmdArr1[0] = 0xbb;
    cmdArr1[1] = 0x04;
    cmdArr1[2] = 0x02;
    cmdArr1[3] = 0x00;
    
    cmdArr1[4] = 0x00;
    
    NSData *dataCmd = [NSData dataWithBytes:cmdArr1 length:5];

    [self.connectPeripheralModel.peripheral writeValue:dataCmd forCharacteristic:self.characteristicFFE4 type:CBCharacteristicWriteWithResponse];
    
}

///绑定指令
- (void) bindCommand {
    
    NSLog(@"bindCommand");
    
    [self.connectPeripheralModel.peripheral setNotifyValue:YES forCharacteristic:self.characteristicFFE3];
    
    unsigned char cmdArr1[20];
    cmdArr1[0] = 0xbb;
    cmdArr1[1] = 0x01;
    cmdArr1[2] = 0x05;
    cmdArr1[3] = 0x00;
    
    cmdArr1[4] = 0x0f;
    
    cmdArr1[5] = 0xb4;
    cmdArr1[6] = 0xf2;
    cmdArr1[7] = 0xc0;
    cmdArr1[8] = 0xcf;
    cmdArr1[9] = 0x33;
    cmdArr1[10] = 0x33;
    
//    cmdArr1[11] = 0x20;
//    cmdArr1[12] = 0x23;
//    cmdArr1[13] = 0x02;
//    cmdArr1[14] = 0x03;
//    cmdArr1[15] = 0x11;
//    cmdArr1[16] = 0x11;
//    cmdArr1[17] = 0x01;
    NSMutableArray<NSNumber *> *timeArray = [PWDigitalUtils toBytesFromNumStr:@"20230710010455"];
    for (int i = 0; i <= 6; i ++) {
        cmdArr1[i+11] = timeArray[i].integerValue;
    }

    cmdArr1[18] = 0x01;
    cmdArr1[19] = 0x0c;
    
    NSData *dataCmd = [NSData dataWithBytes:cmdArr1 length:20];
    NSLog(@"command=%@", dataCmd);

    [self.connectPeripheralModel.peripheral writeValue:dataCmd forCharacteristic:self.characteristicFFE4 type:CBCharacteristicWriteWithResponse];
    
}

- (void) sendCmd:(NSMutableArray<NSNumber *> *) cmdList{
    
    [self.connectPeripheralModel.peripheral setNotifyValue:YES forCharacteristic:self.characteristicFFE3];
    
    unsigned char cmdArr[cmdList.count];
    
    for (int i = 0; i < cmdList.count; i ++) {
        cmdArr[i] = cmdList[i].integerValue;
    }
    
    NSData *dataCmd = [NSData dataWithBytes:cmdArr length:cmdList.count];
    NSLog(@"command=%@", dataCmd);
    
    [self.connectPeripheralModel.peripheral writeValue:dataCmd forCharacteristic:self.characteristicFFE4 type:CBCharacteristicWriteWithResponse];
}

///扫描
- (void) scan {
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        [self.mainManger scanForPeripheralsWithServices:nil options:@{CBCentralManagerScanOptionAllowDuplicatesKey : @NO}];
    });
}

- (void) stopScan {
    [self.mainManger stopScan];
    
    [self.bleArray removeAllObjects];
    [self.peripheralArray removeAllObjects];
}

- (void) startWifiNameTimer {
    
    [self invokeMethodWifiName];
}

- (void) invokeMethodWifiName {
    [self setWifiText:[WifiUtils wifiName]];
    [self.methodChannel invokeMethod:eventWifi arguments:@{@"wifiName": self.wifiText}];
}
#pragma mark 懒加载
- (NSMutableArray<BleModel *> *) bleArray {
    if (!_bleArray) {
        _bleArray = [NSMutableArray array];
    }
    return _bleArray;
}
- (NSMutableArray<CBPeripheral *> *) peripheralArray {
    if (!_peripheralArray) {
        _peripheralArray = [NSMutableArray array];
    }
    return _peripheralArray;
}


#pragma mark 逻辑
- (BOOL) isContainDeviceName:(NSString *) deviceName {
    for (int i = 0; i < self.peripheralArray.count; i ++) {
        CBPeripheral *peripheral = self.peripheralArray[i];
        if ([peripheral.name isEqualToString:deviceName]) {
            return YES;
        }
    }
    
    return NO;
}

- (CBPeripheral *) peripheralWithDeviceName:(NSString *) deviceName {
    for (CBPeripheral *model in self.peripheralArray) {
        if ([model.name isEqualToString:deviceName]) {
            self.peripheral = model;
            return model;
        }
    }
    
    return nil;
}

- (BleModel *) fetchBleModel:(NSString *) deviceName {
    for (BleModel *model in self.bleArray) {
        if ([model.deviceName isEqualToString:deviceName]) {
            return model;
        }
    }
    
    return nil;
}

- (void) appForeground:(NSNotification *) noti {
    NSLog(@"appForeground");
    if (!self.isOpenPushNoti) {
        return;
    }
    
    [self isOpenPush];
}
- (void) isOpenPush {
    ///判断通知权限是否已开启
    if (@available(iOS 10.0, *)) {
        
        [[UNUserNotificationCenter currentNotificationCenter] getNotificationSettingsWithCompletionHandler:^(UNNotificationSettings * _Nonnull settings) {
            
            if (settings.authorizationStatus == UNAuthorizationStatusDenied || settings.authorizationStatus == UNAuthorizationStatusNotDetermined) {
                // 用户未授权开启通知
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                    [dic setValue:@(NO) forKey:@"pushOpen"];
                    [self.methodChannel invokeMethod:eventOpenPushNoti arguments:dic];
                });
            }else if (settings.authorizationStatus == UNAuthorizationStatusAuthorized) {
                //用户已授权开启通知
                dispatch_async(dispatch_get_main_queue(), ^{
                    NSMutableDictionary *dic = [NSMutableDictionary dictionary];
                    [dic setValue:@(YES) forKey:@"pushOpen"];
                    [self.methodChannel invokeMethod:eventOpenPushNoti arguments:dic];
                });
            }
        }];
        
    }
}
#pragma mark 外部方法
- (void) setWifiText:(NSString *)wifiText {
    _wifiText = wifiText;
}
- (void) setMethodChannel:(FlutterMethodChannel *)methodChannel {
    
    ///监听返回前台广播
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(appForeground:) name:ReturnForeGroundNotify object:nil];
    
    _methodChannel = methodChannel;
    
    [methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult  _Nonnull result) {
        
        NSLog(@"原生接收到 %@", call.method);
        if([call.method isEqualToString:eventScanAIO]) {
            [self scan];
            
        } else if([call.method isEqualToString:eventStopScanAIO]) {
            [self stopScan];
            
        } else if([call.method isEqualToString:eventConnectAIO]) {
            NSDictionary *dic = call.arguments;
            
            NSString *deviceName = [dic objectForKey:@"deviceName"];
            NSString *mac = [dic objectForKey:@"mac"];
            
            CBPeripheral *peripheral = [self peripheralWithDeviceName:deviceName];
            if (!peripheral)    return;
//            CBPeripheral *peripheral = self.connectPeripheralModel.peripheral;
            
            [self connectWithPeripheral:peripheral];
            
        } else if([call.method isEqualToString:eventDisConnectAIO]) {
//            NSDictionary *dic = call.arguments;
//
//            NSString *deviceName = [dic objectForKey:@"deviceName"];
//            NSString *mac = [dic objectForKey:@"mac"];
            
//            CBPeripheral *peripheral = [self peripheralWithDeviceName:deviceName];
//            if (!peripheral)    return;
            
            if (self.connectPeripheralModel && self.connectPeripheralModel.peripheral) {
                [self cancelWithPeripheral:self.connectPeripheralModel.peripheral];
            }
            
        } else if([call.method isEqualToString:eventBluetooth]) {
            
            NSDictionary *dict = call.arguments;
            NSMutableArray<NSNumber *> *cmdArray = call.arguments;
            NSLog(@"原生接收到：%@", cmdArray);
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                [self sendCmd:cmdArray];
            });
        } else if ([call.method isEqualToString:eventWifi]) {
//            [self.methodChannel invokeMethod:eventWifi arguments:@{@"wifiName": self.wifiText}];
            [self startWifiNameTimer];
        } 
//        else if ([call.method isEqualToString:eventEndianUser]) {
//            NSDictionary *dic = call.arguments;
//            NSString *userId = [dic objectForKey:@"userId"];
//            NSString *token = [dic objectForKey:@"token"];
//            NSString *time = [dic objectForKey:@"time"];
//            
//            NSArray<NSNumber *> *tokenArray = [PWDigitalUtils getBytesWith:token charsetName:@"GBK" destLen:32];
//            NSArray<NSNumber *> *timeArray = [PWDigitalUtils toBytesFromNumStr:time];
//            NSArray<NSNumber *> *userIdArray = [PWDigitalUtils getBytesWith:userId charsetName:@"GBK" destLen:5];
//            
//            [self.methodChannel invokeMethod:eventEndianUser arguments:@{@"endian": @[tokenArray, timeArray, userIdArray]}];
//        } 
        else if ([call.method isEqualToString:eventEndianWifi]) {
            NSDictionary *dic = call.arguments;
            NSString *wifi = [dic objectForKey:@"wifi"];
            NSString *pass = [dic objectForKey:@"pass"];
            
            NSArray<NSNumber *> *wifiArray = [PWDigitalUtils getBytesWith:wifi charsetName:@"GBK" destLen:64];
            NSArray<NSNumber *> *passArray = [PWDigitalUtils getBytesWith:pass charsetName:@"GBK" destLen:20];
            
            [self.methodChannel invokeMethod:eventEndianWifi arguments:@{@"endian": @[wifiArray, passArray]}];
        } else if ([call.method isEqualToString:eventJumpAppManagerPush]) {
            if (@available(iOS 10.0, *)) {
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
            } else {
                [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs:root=NOTIFICATIONS_ID&path=App的BundleID"] options:@{} completionHandler:nil];
            }
        } else if ([call.method isEqualToString:eventOpenPushNoti]) {
            self.isOpenPushNoti = YES;
            [self isOpenPush];
        } else if ([call.method isEqualToString:eventClosePushNoti]) {
            self.isOpenPushNoti = NO;
        } else if ([call.method isEqualToString:eventBleCentralState]) {
            [self.methodChannel invokeMethod:eventBleCentralState arguments:@{@"BLECentralStatus": @(self.bleCentralStatus)}];
        }
        
    }];
}

@end

